#include "Application.h"
#include "Sniffer.h"
#include "Listener.h"
#include "External.h"
#include "C.h"

namespace Broady {

boost::shared_ptr<Sniffer> Application::GetSniffer( void ) const
{
	return m_Sniffer;
}

boost::shared_ptr<Listener> Application::GetListener( void ) const
{
	return m_Listener;
}

boost::shared_ptr<External> Application::GetExternal( void ) const
{
	return m_External;
}

bool Application::Init( void )
{
	m_Sniffer = boost::shared_ptr<Sniffer>( new Sniffer( ) );

	if( !m_Sniffer )
	{
		return false;
	}

	m_Listener = boost::shared_ptr<Listener>( new Listener( ) );

	if( !m_Listener )
	{
		return false;
	}

	m_External = boost::shared_ptr<External>( new External( ) );

	if( !m_External )
	{
		return false;
	}

	/* load config */
	C_network = C_loadNetwork( "network.txt" );

	boost::optional<PCap::DevicePtrList> alldevs = PCap::ListDevices( );

	if( !alldevs )
	{
		OutputMessage( "Failed to get the list of devices.\n" );

		return false;
	}

	PCap::DevicePtr sniff_dev = PCap::ChooseDevice( "Please select the device on which to listen for data.", *alldevs );

	if( !sniff_dev )
	{
		OutputMessage( "Failed to get sniffing device.\n" );

		return false;
	}

	PCap::DevicePtr emit_dev = PCap::ChooseDevice( "Please select the device to use to transmit the data over the network.", *alldevs );

	if( !emit_dev || emit_dev->m_addresses.empty( ) )
	{
		OutputMessage( "Failed to get transmitting device.\n" );

		return false;
	}

	if( !m_Sniffer->Init( sniff_dev ) )
	{
		OutputMessage( "Failed to initialize sniffer.\n" );

		return false;
	}

	if( !m_External->Init( *emit_dev->m_addresses[0].m_addr ) )
	{
		OutputMessage( "Failed to initialize external.\n" );

		return false;
	}

	OutputMessage( "Listening on %s\n", sniff_dev->m_description.c_str( ) );
	OutputMessage( "Transmitting on %s\n\n", emit_dev->m_description.c_str( ) );

	return true;
}

bool Application::Step( void )
{
	if( !m_Sniffer->Step( ) )
	{
		OutputMessage( "Sniffer failed.\n" );

		return false;
	}

	if( !m_External->Step( ) )
	{
		OutputMessage( "External failed.\n" );

		return false;
	}

	return true;
}

void Application::Quit( void )
{
	m_Sniffer->Quit( );
	m_External->Quit( );
}

void Application::DoLoop( void )
{
	while( this->Step( ) )
	{
		Sleep( 10 );	// Give some time to the other processes
	}
}

} // namespace
